<?php


namespace Drupal\wx_pay_refund;


use Drupal\wx_pay\EasyWechatApp;
use Drupal\wx_pay\Entity\WxPayTransaction;
use Drupal\wx_pay_refund\Entity\WxPayRefundRecord;
use DrupalQueue;
use DrupalQueueInterface;

abstract class WxPayRefundBaseController extends EasyWechatApp {

  protected $easyWechat;

  protected $payment;

  public function __construct() {
    $this->easyWechat = $this;
    $this->payment = $this->getPayment();
    return $this;
  }

  function processingQueueAWorkerCallback(WxPayRefundRecord $wxPayRefundRecord) {
    if ($wxPayRefundRecord->result_code == 'SUCCESS') {
      if (!empty($wxPayRefundRecord->refund_id)) {
        //正常退款不处理
        return;
      }
    }
    switch ($wxPayRefundRecord->err_code) {
      case 'SYSTEMERROR':
      case 'BIZERR_NEED_RETRY':
        //请不要更换商户退款单号，请使用相同参数再次调用API。
        $result = $this->retryRefund($wxPayRefundRecord);
        foreach ($result as $key => $value) {
          $wxPayRefundRecord->{$key} = $value;
        }
        $wxPayRefundRecord->save();
        if (empty($wxPayRefundRecord->refund_id)) {
          $queue_name = 'wx_pay_refund_processing_queue_b';
          $queue = DrupalQueue::get($queue_name);
          if ($queue instanceof DrupalQueueInterface) {
            $queue->createItem($wxPayRefundRecord);
          }
        }
        break;
      case 'NOTENOUGH':
        //商户可用退款余额不足
        //0.006 的手续费  如果只有一笔支付  资金不够。 分成多笔退款  先退本金  在退手续费
        $module = $wxPayRefundRecord->module;
        $wxPayTransaction = entity_load_single('wx_pay_transaction', $wxPayRefundRecord->wx_pay_transaction);
        $refund_fee = 0;
        $refund_desc = $wxPayRefundRecord->refund_reason;
        $this->refundTransaction($module, $wxPayTransaction, $refund_fee, $refund_desc, $wxPayRefundRecord->attach);
        break;
      case 'TRADE_OVERDUE':
      case 'ERROR':
      case 'USER_ACCOUNT_ABNORMAL':
      case 'INVALID_REQ_TOO_MUCH':
      case 'INVALID_TRANSACTIONID':
      case 'PARAM_ERROR':
      case 'APPID_NOT_EXIST':
      case 'MCHID_NOT_EXIST':
      case 'REQUIRE_POST_METHOD':
      case 'SIGNERROR':
      case 'XML_FORMAT_ERROR':
      case 'FREQUENCY_LIMITED':
        watchdog('退款失败', serialize($wxPayRefundRecord), [], WATCHDOG_ERROR);
        break;
    }
  }

  protected function retryRefund(WxPayRefundRecord $wxPayRefundRecord) {
    $wxPayTransaction = entity_load_single('wx_pay_transaction', $wxPayRefundRecord->wx_pay_transaction);

    $out_trade_no = $wxPayTransaction->out_trade_no;
    $out_refund_no = $wxPayRefundRecord->out_refund_no;
    $total_fee = $wxPayRefundRecord->total_fee;
    $refund_fee = $wxPayRefundRecord->refund_fee;
    $refund_desc = $wxPayRefundRecord->refund_reason;

    return $this->getPayment()->refund->byOutTradeNumber($out_trade_no, $out_refund_no, $total_fee, $refund_fee, ['refund_desc' => $refund_desc,]);
  }

  function refundTransaction(string $module, WxPayTransaction $wxPayTransaction, $refund_fee = 0, $refund_desc = '', string $attach = '') {
    $out_refund_no = $this->makeOutRefundNo();
    $out_trade_no = $wxPayTransaction->out_trade_no;

    $total_fee = $wxPayTransaction->total_fee;
    if ($refund_fee < 1) {
      //如果退款金额小于1 则表示全退
      $refund_fee = $total_fee;
    }
    //自动计算退款金额 如果金额大于剩余退款金额 则全退
    $tmp = 0;
    $refunds = wx_pay_refund_record_multiple(FALSE, [
      'wx_pay_transaction' => $wxPayTransaction->identifier(),
      'status' => 1,
    ]);
    foreach ($refunds as $refund) {
      if ($refund instanceof WxPayRefundRecord) {
        $tmp += $refund->refund_fee;
      }
    }
    if ($wxPayTransaction->total_fee - $tmp < $refund_fee) {
      $refund_fee = $wxPayTransaction->total_fee - $tmp;
    }

    $result = $this->refund($out_trade_no, $out_refund_no, $total_fee, $refund_fee, $refund_desc);
    $refund = new WxPayRefundRecord($result);
    $refund->module = $module;
    $refund->attach = $attach;
    $refund->wx_pay_transaction = $wxPayTransaction->identifier();
    $refund->refund_reason = $refund_desc;
    $refund->total_fee = $total_fee;
    $refund->refund_fee = $refund_fee;
    $refund->save();

    return $refund;
  }

  protected function makeOutRefundNo() {
    return $this->makeOutTradeNo();
  }

  protected function refund($out_trade_no, $out_refund_no, $total_fee, $refund_fee, $refund_desc) {
    return $this->getPayment()->refund->byOutTradeNumber($out_trade_no, $out_refund_no, $total_fee, $refund_fee, [
      'refund_desc' => $refund_desc,
      'notify_url' => $this->getNotifyUrl(),
    ]);
  }

  function processingQueueBWorkerCallback(WxPayRefundRecord $wxPayRefundRecord) {
    if ($wxPayRefundRecord->result_code == 'SUCCESS') {

    }
    switch ($wxPayRefundRecord->err_code) {
      case 'SYSTEMERROR':
        break;
      case 'BIZERR_NEED_RETRY':
        break;
      case 'TRADE_OVERDUE':
        break;
      case 'ERROR':
        break;
      case 'USER_ACCOUNT_ABNORMAL':
        break;
      case 'INVALID_REQ_TOO_MUCH':
        break;
      case 'NOTENOUGH':
        break;
      case 'INVALID_TRANSACTIONID':
        break;
      case 'PARAM_ERROR':
        break;
      case 'APPID_NOT_EXIST':
        break;
      case 'MCHID_NOT_EXIST':
        break;
      case 'REQUIRE_POST_METHOD':
        break;
      case 'SIGNERROR':
        break;
      case 'XML_FORMAT_ERROR':
        break;
      case 'FREQUENCY_LIMITED':
        break;
    }
  }

  function notifyCallback() {
    try {
      $response = $this->payment->handleRefundedNotify(function ($message, $reqInfo, $fail) {
        if ($message['return_code'] == 'SUCCESS') {
          $out_refund_no = $reqInfo['out_refund_no'];
          if ($reqInfo['refund_status'] == 'SUCCESS') {
            $refunds = wx_pay_refund_record_multiple(FALSE, ['out_refund_no' => $out_refund_no]);
            if (!empty($refunds)) {
              $refund = reset($refunds);
              if ($refund instanceof WxPayRefundRecord) {
                module_invoke($refund->module, 'wx_pay_refund_notify', $refund);
                module_invoke_all('wx_pay_refund_common_notify', $refund);
              }
            }
          }
        }
        else {
          return $fail('通信失败，请稍后再通知我');
        }
        return TRUE;
      });
      $response->sendContent();
    } catch (WxPayRefundException $e) {
      watchdog_exception(__FUNCTION__, $e);
    }
  }

  function getNotifyUrl() {
    global $base_url;
    return $base_url . '/wx_pay_refund/notify_url';
  }

  protected function getIndexNumber() {
    $old_index = variable_get('wx_pay_refund:index_number', 0);
    if ($old_index > 98) {
      $new_index = 0;
    }
    else {
      $new_index = $old_index + 1;
    }
    variable_set('wx_pay_refund:index_number', $new_index);
    return $old_index;
  }
}
